package com.spukmk3me.video;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.events.XMLEvent;

import com.spukmk3me.Platform;
import com.spukmk3me.io.FileHandle;
import com.spukmk3me.io.FileSystem;
import com.spukmk3me.math.Rectangle;
import com.spukmk3me.resource.Resource;
import com.spukmk3me.resource.ResourceManager;
import com.spukmk3me.util.Util;

public abstract class Font extends Resource
{
    public final boolean isSupported( char c )
    {
        return m_charMap.indexOf( c ) != -1;
    }

    public final int getLineHeight()
    {
        return m_lineHeight;
    }
    
    public final int getSpaceBetweenChar()
    {
        return m_spaceBetweenChar;
    }
    
    public final Rectangle getCharacterDimension( char c )
    {
        int index = m_charMap.indexOf( c );
        
        if ( index == -1 )
            return null;
        
        return m_dimensions[ index ];
    }
    
    public final Image getImage()
    {
        return m_texture;
    }
    
    @Override
    protected final int _load() throws IOException
    {
        InputStream is = getFileHandle().openFileForReading();
        
        try
        {
            XMLInputFactory factory = XMLInputFactory.newInstance();
            XMLStreamReader reader = factory.createXMLStreamReader( is );
            
            resetReader();
            
            while ( reader.hasNext() )
                read( reader );
            
            reader.close();
        } catch ( FactoryConfigurationError e ) {
            e.printStackTrace();
            return -1;
        } catch ( XMLStreamException e ) {
            e.printStackTrace();
            return -1;            
        }
        
        ResourceManager resMan = Platform.PLATFORM.getResourceManager();
        FileSystem fsys = Platform.PLATFORM.getFileSystem();
        FileHandle textureHandle = fsys.createFileHandle(
            Util.convertToAbsolutePath(
                getFileHandle().getParentDirectory(),
                m_readerTexturePath,
                File.separatorChar, '/' ),
            m_readerTextureLocation
        );
        
        m_texture = (Image)resMan.loadResource( textureHandle, "image" );
        return 0;
    }
    
    private void read( XMLStreamReader reader ) throws XMLStreamException
    {
        reader.next();
        
        switch ( reader.getEventType() )
        {
            case XMLEvent.START_DOCUMENT:
                break;
                
            case XMLEvent.END_DOCUMENT:
                break;
                
            case XMLEvent.START_ELEMENT:
                if ( reader.getLocalName().equals( CHAR ) )
                {
                    if ( m_readerState == RS_READDIMENSION )
                    {
                        char id = reader.getAttributeValue( 0 ).charAt( 0 );
                        int x = Integer.parseInt( reader.getAttributeValue( 1 ) );
                        int y = Integer.parseInt( reader.getAttributeValue( 2 ) );
                        int w = Integer.parseInt( reader.getAttributeValue( 3 ) );
                        int h = Integer.parseInt( reader.getAttributeValue( 4 ) );
                        
                        m_dimensions[ m_charMap.indexOf( id ) ] = new Rectangle( x, y, w, h );
                    }
                }
                else if ( reader.getLocalName().equals( TEXTURE ) )
                {
                    m_readerState = RS_READTEXTURE;
                    m_readerTexturePath = reader.getAttributeValue( 0 );
                    
                    String loc = reader.getAttributeValue( 1 ); 
                    
                    if ( loc.equals( INTERNAL ) )
                        m_readerTextureLocation = FileHandle.LOC_INTERNAL;
                    else if ( loc.equals( EXTERNAL ) )
                        m_readerTextureLocation = FileHandle.LOC_EXTERNAL;
                    else if ( loc.equals( REMOTE ) )
                        m_readerTextureLocation = FileHandle.LOC_REMOTE;
                }
                else if ( reader.getLocalName().equals( CHARMAP ) )
                    m_readerState = RS_READCHARMAP;
                else if ( reader.getLocalName().equals( DIMENSIONS ) )
                    m_readerState = RS_READDIMENSION;
                else if ( reader.getLocalName().equals( FONT ) )
                    m_readerState = RS_DONE;
                break;
                
            case XMLEvent.CDATA:
                if ( m_readerState == RS_READCHARMAP )
                {
                    m_charMap = reader.getText();
                    m_dimensions = new Rectangle[ m_charMap.length() ];
                }
                
                break;
        }
    }
    
    private void resetReader()
    {
        m_readerState = RS_STANDBY;
        m_readerTexturePath = null;
        m_readerTextureLocation = FileHandle.LOC_INTERNAL;
    }
    
    @Override
    protected final void _release()
    {
        m_texture.dec();
        m_texture = null;
        m_dimensions = null;
        m_charMap = null;
    }
    
    private static final String TEXTURE     = "texture";
    private static final String CHARMAP     = "charmap";
    private static final String DIMENSIONS  = "dimension";
    private static final String CHAR        = "char";
    private static final String FONT        = "font";
    private static final String INTERNAL    = "internal";
    private static final String EXTERNAL    = "external";
    private static final String REMOTE      = "remote";
    
    private Image m_texture;
    private String m_charMap;
    private Rectangle[] m_dimensions;
    private int m_lineHeight, m_spaceBetweenChar;
    
    // Variables and constants for reader
    private static final byte RS_STANDBY        = 0;
    private static final byte RS_READTEXTURE    = 1;
    private static final byte RS_READCHARMAP    = 2;
    private static final byte RS_READDIMENSION  = 3;
    private static final byte RS_DONE           = 5;
    
    private byte    m_readerState;
    private String  m_readerTexturePath;
    private byte    m_readerTextureLocation;
}